package astra.server;

import astra.client.models.*;
import astra.client.services.AstraService;
import astra.client.services.Filter;
import astra.client.services.HasId;
import astra.server.security.AccessControlServlet;
import astra.server.security.AccessDeniedException;
import com.google.gwt.user.client.rpc.IsSerializable;

import java.util.ArrayList;
import java.util.List;

public class AstraServiceImpl extends AccessControlServlet implements AstraService {

    @Override
	public Employee getEmployee() {
		return threadLocalEmployee.get();
	}

    protected SqlFilter getFilter(IsSerializable filter, String startsWith) {
        List<Object> params = new ArrayList<Object>();
        StringBuilder query = new StringBuilder();
        String where = query.toString();
        if (!where.isEmpty()) {
            where = startsWith + " " + where;
        } else {
            where = "";
        }
        return new SqlFilter(where, params);
    }

    @Override
    public AstraData getAstraData() {
        return new AstraData(
            get(Client.class),
            get(Supplier.class),
            get(Employee.class)
        );
    }

    public <T> List<T> get(Class<T> modelClass) {
        Employee employee = threadLocalEmployee.get();
        String tableName = getTableName(modelClass);
        Employee.Access access = employee.getAccess(tableName);

        if (access == Employee.Access.DENIED) {
            return null;
        }

        return jdbcTemplate.query(
            "select * from " + tableName, getMapper(modelClass)
        );
    }

    public SqlFilter applyFilter(PurchaseFilter filter, String where) {
        List<Object> params = new ArrayList<Object>();
        StringBuilder query = new StringBuilder();
        return new SqlFilter(query.toString(), params);
    }

    @Override
    public TableRequestResult<Purchase> getPurchase(int page, int rowsPerPage, boolean requestRowsCount,
                                                    PurchaseFilter filter) {
        Employee employee = threadLocalEmployee.get();
        Employee.Access access = employee.getAccess("purchase");

        if (access == Employee.Access.DENIED) {
            throw new AccessDeniedException();
        }

        SqlFilter sqlFilter = applyFilter(filter, "where ");

        int count = -1;
        if (requestRowsCount) {
            count = jdbcTemplate.queryForInt(
                "select count(*) from purchase, client, supplier, employee account, employee manager " +
                "where purchase.client_id = client.id and purchase.supplier_id = supplier.id " +
                "and account.id = purchase.account_id and manager.id = purchase.manager_id " +
                sqlFilter.query,
                sqlFilter.params.toArray()
            );
        }
        List<Object> params = sqlFilter.params;
        params.add((page - 1)*rowsPerPage);
        params.add(rowsPerPage);
        List<Purchase> rows = jdbcTemplate.query(
            "select purchase.*, account.name as account, manager.name as manager, " +
            "client.name as client, supplier.name as supplier " +
            "from purchase, client, supplier, employee manager, employee account " +
            "where purchase.client_id = client.id " +
            "and purchase.supplier_id = supplier.id and purchase.manager_id = manager.id " +
            "and purchase.account_id = account.id "+sqlFilter.query+" limit ?,?",
            getMapper(Purchase.class),
            params.toArray()
        );
        return new TableRequestResult<Purchase>(count, rows);
    }

    private class SqlFilter{
        public final String query;
        public final List<Object> params;

        private SqlFilter(String query, List<Object> params) {
            this.query = query;
            this.params = params;
        }
    }
}